#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include <QtWidgets>

QColor activeColor = Qt::darkGreen;// 初始化活细胞的颜色为深绿色

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),generationCount(0),liveCells(0)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 向颜色组合框添加颜色选项及关联数据
    ui->colorComboBox->addItem("绿色", QColor(Qt::darkGreen));
    ui->colorComboBox->addItem("红色", QColor(Qt::red));
    ui->colorComboBox->addItem("蓝色", QColor(Qt::blue));
    ui->colorComboBox->addItem("黄色", QColor(Qt::yellow));

    // 连接信号到槽函数
    connect(ui->colorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::on_colorComboBox_activated);
    connect(ui->startButton, &QPushButton::clicked, this, &MainWindow::startGame);
    connect(ui->pauseButton, &QPushButton::clicked, this, &MainWindow::pauseGame);
    connect(ui->resetButton, &QPushButton::clicked, this, &MainWindow::resetGame);
    connect(ui->randomButton, &QPushButton::clicked, this, &MainWindow::randomizeCells);

    // 按钮启用状态
    ui->pauseButton->setEnabled(false);// 开始时暂停按钮不可用

    // 初始化细胞矩阵为全false（即全死亡状态）
    cells = std::vector<std::vector<bool>>(rows, std::vector<bool>(cols, false));

    // 创建定时器并连接其timeout信号
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &MainWindow::nextGeneration);

    // 初始化游戏状态
    resetGame();
}

MainWindow::~MainWindow()
{
    delete ui;
}
// 重写绘图事件处理函数，用于绘制游戏界面
void MainWindow::paintEvent(QPaintEvent * /*event*/)
{
    QPainter painter(this);
    // 设置背景颜色为白色，使用 fillRect 函数填充整个窗口矩形区域
    painter.fillRect(rect(), Qt::white);

    // 画细胞
    painter.setPen(Qt::NoPen);// 以无边框形式绘制（仅填充颜色），优化细胞绘制效果
    // 遍历所有细胞，根据当前状态绘制细胞
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            if (cells[i][j])// 如果当前细胞存活（值为true），使用预设的激活颜色填充该细胞位置
            {
                painter.fillRect(j * cellSize, i * cellSize, cellSize, cellSize, activeColor);
            }
            else// 否则，用黑色填充表示细胞处于非激活状态（死亡）
            {
                painter.fillRect(j * cellSize, i * cellSize, cellSize, cellSize, Qt::black);
            }
        }
    }
}

// 下一代逻辑处理函数
void MainWindow::nextGeneration()
{
    // 初始化一个与当前细胞状态同样大小的二维向量，用于存储下一代细胞的状态，初始值均为false（代表细胞死亡）
    std::vector<std::vector<bool>> nextGen(rows, std::vector<bool>(cols, false));

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            // 计算当前细胞周围的活细胞数量
            int liveNeighbors = countNeighbors(i, j);
            // 应用Conway's Game of Life规则：
            // 1. 任何活着的细胞，如果周围有2个或3个活细胞，则在下一次迭代中存活。
            // 2. 任何死了的细胞，如果恰好有3个活细胞相邻，则在下一次迭代中复活。
            // 3. 其他情况下, 下一次迭代中均死亡。
            if ((cells[i][j] && (liveNeighbors == 2 || liveNeighbors == 3)) || (!cells[i][j] && liveNeighbors == 3))
            {
                nextGen[i][j] = true;
            }
        }
    }

    // 更新细胞状态到新一代，使用swap避免复制整个二维向量，提高效率
    cells.swap(nextGen);

    generationCount++;
    // 更新UI显示的迭代次数
    ui->generationLabel->setText(QString("迭代次数: %1").arg(generationCount));
    // 重新计算当前活细胞的数量
    countLiveCells();
    update();
}

// 统计并更新活细胞数量
void MainWindow::countLiveCells()
{
    liveCells = 0;
    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j < cols; j++)
        {
            if (cells[i][j])
            {
                liveCells++;
            }
        }
    }
    ui->liveCellsLabel->setText(QString("活细胞: %1").arg(liveCells));
}

// 计算给定单元格周围活细胞的数量
int MainWindow::countNeighbors(int row, int col) const
{
    int count = 0;
    // 遍历当前细胞周围的每个邻居位置
    for (int i = -1; i <= 1; i++)// 上下邻居
    {
        for (int j = -1; j <= 1; j++)// 左右邻居
        {
            if (i == 0 && j == 0) continue;// 跳过当前细胞自身（中心点）
            // 使用取模运算处理边缘情况，使得当索引超出边界时能够循环回网格的另一侧
            int r = (row + i + rows) % rows;
            int c = (col + j + cols) % cols;
            // 如果邻居是活细胞（cells[r][c]为true），累加计数器
            count += cells[r][c];
        }
    }
    return count;
}

// 开始游戏逻辑
void MainWindow::startGame()
{
    timer->start(100);
    ui->startButton->setEnabled(false);
    ui->pauseButton->setEnabled(true);
    ui->randomButton->setEnabled(false);
}

// 暂停游戏逻辑
void MainWindow::pauseGame()
{
    timer->stop();
    ui->startButton->setEnabled(true);
    ui->pauseButton->setEnabled(false);
}

// 重置游戏状态
void MainWindow::resetGame()
{
    timer->stop();
    //将cells这个二维布尔数组重新初始化为指定的行数（rows）和列数（cols），并且所有细胞初始状态均为死亡（false）
    cells.assign(rows, std::vector<bool>(cols, false));
    generationCount=0;//迭代次数重置为0
    liveCells=0;//活细胞数重置为0
    update();
    ui->startButton->setEnabled(true);
    ui->pauseButton->setEnabled(false);
    ui->randomButton->setEnabled(true);
}

// 随机化细胞状态
void MainWindow::randomizeCells()
{
    std::random_device rd;// 用于获取随机数的种子
    std::mt19937 gen(rd());// 使用Mersenne Twister算法生成随机数
    std::uniform_int_distribution<> dis(0, 1);// 定义一个均匀分布，范围从0到1
    // 遍历cells数组中的每个元素，使用随机数生成器决定细胞的生死状态
    for (int y = 0; y < rows; ++y)
    {
        for (int x = 0; x < cols; ++x)
        {
            cells[y][x] = dis(gen) == 1; // 如果随机数为1，则细胞为活；否则为死
        }
    }

    // 更新界面显示
    update();

}

// 处理鼠标点击事件，切换细胞状态
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    // 当鼠标按下时，调用toggleCell函数切换鼠标当前位置所对应的细胞状态
    toggleCell(event->pos());
    // 设置拖动标志为true，表示用户已经开始拖动操作
    isDragging = true;
}

// 处理鼠标移动事件，持续切换细胞状态（如果正在拖动）
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    // 如果拖动标志为true（即用户正在拖动鼠标），则持续调用toggleCell函数以切换鼠标当前位置所对应的细胞状态，实现连续切换的效果
    if (isDragging)
    {
        toggleCell(event->pos());
    }
}

// 处理鼠标释放事件，停止拖动状态
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    isDragging = false; // 结束拖动
}

// 处理用户点击或拖动鼠标来改变细胞的状态
void MainWindow::toggleCell(const QPoint &point)
{
    // 计算鼠标点击位置对应的细胞网格的行索引(x坐标)和列索引(y坐标)。
    int x = point.x() / cellSize;// 将点击点的x坐标除以单个细胞的宽度(cellSize)得到列索引x
    int y = point.y() / cellSize; // 将点击点的y坐标除以单个细胞的高度(cellSize)得到行索引y
    // 检查计算出的行索引y和列索引x是否在当前网格的有效范围内
    // 如果索引超出范围，则不执行任何操作，以避免数组越界错误
    if (x >= 0 && x < cols && y >= 0 && y < rows)
    {
        cells[y][x] = !cells[y][x]; // 切换对应位置的细胞状态。如果当前细胞是活的，则设为死；如果是死的，则设为活。
        update();
    }
}

// 颜色组合框选中项变化时调用，更新活细胞颜色
void MainWindow::on_colorComboBox_activated(int index)
{
    activeColor = qvariant_cast<QColor>(ui->colorComboBox->itemData(index)); // 获取所选颜色
    update(); // 触发重绘以便应用新颜色
}
